import { mapTo, share } from "rxjs/operators";
import { Action } from "redux";
import { merge, Observable, of } from "rxjs";

export interface StateLoading {
  [key: string]: boolean;
}

export class ActionSetLoading implements Action {
  constructor(public readonly type: string, public payload: StateLoading) {}
}

export function wrapLoading<T extends Action>(
  data$: Observable<Action>,
  key: string,
  setLoadingType: string
): Observable<T | ActionSetLoading> {
  const share$ = data$.pipe(share());

  const startLoading$ = of({
    ...new ActionSetLoading(setLoadingType, { [key]: true })
  });

  const endLoading$ = share$.pipe(
    mapTo({ ...new ActionSetLoading(setLoadingType, { [key]: false }) })
  );

  return merge<ActionSetLoading, T, ActionSetLoading>(
    startLoading$,
    share$,
    endLoading$
  );
}
